#include "SavingAccount.hh"
#include "AccountUtils.hh"
#include "CheckingAccount.hh"
#include "BankSystem.hh"
#include "IO.hh"
#include <iostream>
#include <sstream>
#include <iomanip>
#include <fstream>
#include <ctime>

namespace {
    std::string getCurrentDate() {
        char buf[11];
        std::time_t now = std::time(nullptr);
        std::strftime(buf, sizeof(buf), "%Y-%m-%d", std::localtime(&now));
        return buf;}
}
namespace Bank {
    SavingsAccount::SavingsAccount(const std::string& id, const std::string& owner, double initBal)
        : accountId(id), ownerName(owner), balance(initBal) {}

    std::string SavingsAccount::getAccountId() const { return accountId; }
    std::string SavingsAccount::getOwnerName() const { return ownerName; }
    std::string SavingsAccount::getAccountType() const { return "Savings"; }
    double SavingsAccount::getBalance() const { return balance; }

    std::string SavingsAccount::getFormattedBalance() const {
        std::ostringstream oss;
        oss << "(CNY)" << std::fixed << std::setprecision(2) << balance;
        return oss.str();}

    bool SavingsAccount::transferTo(IAccount* to, double amt, const std::string& note) {
        if (amt <= 0 || amt > balance || !canTransferTo(to)) {
            std::cout << "Transfer failed.\n";
            return false;}
        balance -= amt;
        to->receiveTransfer(amt); // The target account receives the transfer amount
        std::cout << "Transfer successful: " << accountId << " -> " << to->getAccountId() << "\n";
        return true;}

    void SavingsAccount::displayInfo() const {
        std::cout << "Savings Account: " << accountId << "\nOwner: " << ownerName
                  << "\nBalance: " << getFormattedBalance() << "\n";}

    void SavingsAccount::deposit(double) {
        std::cout << "Deposit not permitted for savings accounts from interface.\n";}

    void SavingsAccount::internalDeposit(double amt) {
        if (amt > 0) {
            balance += amt;
            std::cout << "Internal deposit of " << amt << " to " << accountId << "\n";}
    }

    void SavingsAccount::receiveTransfer(double amt) {
        if (amt > 0) {
            balance += amt;
            std::cout << "Received transfer of " << amt << " to " << accountId << "\n";}
    }

    bool SavingsAccount::withdraw(double) {
        std::cout << "Withdrawal not permitted for savings accounts from interface.\n";
        return false;}

    bool SavingsAccount::canTransferTo(IAccount* to) const {
        return to->getOwnerName() == ownerName && to->getAccountType() == "Checking";}

    // The account operation interface allows users to select transfer, view history, or generate reports.
    void SavingsAccount::accessAccountInterface(const std::string& customerName, const std::vector<Transaction>& allTxs) {
        while (true) {
            std::cout << "\n===== Bank Account: " << accountId << " (Savings Account) =====\n"<< "Account holder: " << customerName << "\nBalance: " << getFormattedBalance()
                      << "\n\n1. Transfer to your checking account\n2. View transaction history"<< "\n3. Generate bank account report\n4. Return to customer page\nPlease choose: ";

            int choice = IO::getNumber();

            if (choice == 4) return; // Log out of the account interface

            if (choice == 1) {
                auto accounts = BankSystem::getInstance().findAccountsByOwner(customerName);
                IAccount* target = nullptr;
                for (const auto& acc : accounts)
                    if (acc->getAccountType() == "Checking") target = acc.get();
                if (!target) {
                    std::cout << "No linked checking account found.\n";
                    continue;}
                double amt;
                std::string note;
                std::cout << "Enter amount to transfer: ";
                amt = IO::getAmount();

                std::cout << "Enter note (optional): ";
                note = IO::getString();

                if (transferTo(target, amt, note))
                    BankSystem::getInstance().recordTransaction(
                        Transaction(Transaction::generateUniqueTransactionID(), TransactionType::Transfer, amt, accountId, target->getAccountId(), note));}
            else if (choice == 2) {
                std::cout << "\n=== Transactions for " << accountId << " ===\n";
                for (const auto& tx : allTxs)
                    if (tx.involvesAccount(accountId)) std::cout << tx.toString() << "\n"; }
            else if (choice == 3) {
                std::string filename = "transactions_" + accountId + "_" + getCurrentDate() + ".txt";
                std::ofstream outFile(filename);
                for (const auto& tx : allTxs)
                    if (tx.involvesAccount(accountId)) outFile << tx.toString() << "\n";
                std::cout << "Report saved to: " << filename << "\n";}
            else std::cout << "Invalid option.\n";
        }
    }
}